package com.clp.protocol.iec104.client.pipeline;

import com.clp.protocol.iec104.apdu.Apdu;
import com.clp.protocol.iec104.client.Master;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
 * 与主站绑定的处理器，含有一个 master 变量，该变量属于 该handler的主站的一个 channel
 */
@Slf4j
public abstract class DuplexMasterHandler extends ChannelDuplexHandler {
    // 该处理器绑定的 主站
    protected final Master master;

    public DuplexMasterHandler(@NonNull Master master) {
        this.master = master;
    }

    /**
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        whenActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        whenRecvingApdu(ctx, (Apdu) msg);
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        whenSendingApdu(ctx, (Apdu) msg, promise);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        whenInActive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        whenExceptionCaught(ctx, cause);
    }

    /**
     *
     * @param ctx
     * @throws Exception
     */
    public abstract void whenActive(ChannelHandlerContext ctx) throws Exception;

    protected void passActive(ChannelHandlerContext ctx) {
        ctx.fireChannelActive();
    }

    public abstract void whenRecvingApdu(ChannelHandlerContext ctx, Apdu apdu);

    protected void passRecvingApdu(ChannelHandlerContext ctx, Apdu apdu) {
        ctx.fireChannelRead(apdu);
    }

    public abstract void whenSendingApdu(ChannelHandlerContext ctx, Apdu apdu, ChannelPromise promise);

    protected void passSendingApdu(ChannelHandlerContext ctx, Apdu apdu, ChannelPromise promise) {
        ctx.write(apdu, promise);
    }

    public abstract void whenInActive(ChannelHandlerContext ctx) throws Exception;

    protected void passInActive(ChannelHandlerContext ctx) {
        ctx.fireChannelInactive();
    }

    public abstract void whenExceptionCaught(ChannelHandlerContext ctx, Throwable cause);

    protected void passExceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.fireExceptionCaught(cause);
    }
}
